#include "Animation.h"

Animation::Animation(int id, IRenderable *model)
{
	this ->id = id;
	this ->model = model;
	this ->animatable = NULL;

	tcbKeyInterpolator = NULL;
	time = 0.0f;
	animatablesTime = 0.0f;
}

Animation * Animation::LoadAnimation(Animation *parent, FileHolder *fh)
{
	Animation *anim = new Animation(0, NULL);

	if (parent != NULL)
	{
		int id = fh ->readInt();
		fh ->readBuffer((BYTE*)(anim ->itm), sizeof(float) * 4 * 4);

		anim ->id = id;

		int keysCount = fh ->readInt();

		if (keysCount > 0)
		{
			anim ->tcbKeyInterpolator = new TCBKeyInterpolator();
			anim ->tcbKeyInterpolator ->pos = new TCBVec3Interpolator();
			anim ->tcbKeyInterpolator ->rot = new TCBRotInterpolator();
			anim ->tcbKeyInterpolator ->scale = new TCBVec3Interpolator();
			anim ->tcbKeyInterpolator ->roll = new TCBFloatInterpolator();

			for (int i = 0; i < keysCount; i++)
			{
				TcbKey tcbKey;
				fh ->readBuffer((BYTE*)&tcbKey, sizeof(TcbKey));

				anim ->tcbKeyInterpolator ->pos ->AddKey((float)tcbKey.time, tcbKey.pos);
				anim ->tcbKeyInterpolator ->rot ->AddKey((float)tcbKey.time, tcbKey.angle, tcbKey.axis);
				anim ->tcbKeyInterpolator ->scale ->AddKey((float)tcbKey.time, tcbKey.scale);
				anim ->tcbKeyInterpolator ->roll ->AddKey((float)tcbKey.time, tcbKey.roll);
			}
		}
	}

	int childAnims = fh ->readInt();
	for (int i = 0; i < childAnims; i++)
		anim ->subAnims.push_back(LoadAnimation(anim, fh));

	return anim;
}

Animation * Animation::LoadFromFile(const char *filename)
{
	FileHolder *fh = new FileHolder();
	fh ->openToRead(filename);
	Animation *anim = LoadAnimation(NULL, fh);
	fh ->close();
	delete fh;

	return anim;
}

//TODO: to ma byc zwykly process!! teraz tylko tak zrobilem bo jest malo czasu
void Animation::ProcessAnimatables(float ms)
{
	if (animatable != NULL)
	{
		if (tcbKeyInterpolator != NULL)
		{
			sm::Vec3 pos(0, 0, 0);
			sm::Vec3 axis(1, 0, 0);
			sm::Vec3 scale(1.0f, 1.0f, 1.0f);
			float angle = 0.0f;
			float roll = 0.0f;

			if (tcbKeyInterpolator ->pos != NULL)
				tcbKeyInterpolator ->pos ->GetValue(time, pos);

			if (tcbKeyInterpolator ->rot != NULL)
				tcbKeyInterpolator ->rot ->GetValue(time, angle, axis);

			if (tcbKeyInterpolator ->scale != NULL)
				tcbKeyInterpolator ->scale ->GetValue(time, scale);

			if (tcbKeyInterpolator ->roll != NULL)
				tcbKeyInterpolator ->roll ->GetValue(time, roll);

			animatable ->SetPosition(pos);
			animatable ->SetRotation(angle, axis);
			animatable ->SetScale(scale);
			animatable ->SetRoll(roll);
		}
	}

	std::vector<Animation*>::iterator i;
	for (i = subAnims.begin(); i != subAnims.end(); i++)
		(*i) ->ProcessAnimatables(ms);

	animatablesTime += ms;
}

void Animation::Process(float ms)
{
	if (model != NULL)
		model ->Process(ms);

	std::vector<Animation*>::iterator i;
	for (i = subAnims.begin(); i != subAnims.end(); i++)
		(*i) ->Process(ms);

	time += ms;
}

void Animation::Render()
{
	glPushMatrix();

	if (tcbKeyInterpolator != NULL)
	{
		sm::Vec3 pos(0, 0, 0);
		sm::Vec3 axis(1, 0, 0);
		sm::Vec3 scale(1.0f, 1.0f, 1.0f);
		float angle = 0.0f;
		float roll = 0.0f;

		if (tcbKeyInterpolator ->pos != NULL)
			tcbKeyInterpolator ->pos ->GetValue(time, pos);

		if (tcbKeyInterpolator ->rot != NULL)
			tcbKeyInterpolator ->rot ->GetValue(time, angle, axis);

		if (tcbKeyInterpolator ->scale != NULL)
			tcbKeyInterpolator ->scale ->GetValue(time, scale);

		if (tcbKeyInterpolator ->roll != NULL)
			tcbKeyInterpolator ->roll ->GetValue(time, roll);

		glTranslatef(pos.x, pos.y, pos.z);
		glRotatef(deg(angle), axis.x, axis.y, axis.z);
		glScalef(scale.x, scale.y, scale.z);

		glPushMatrix();
		glMultMatrixf(itm);
	}

	/*if (model != NULL)
		model ->Render();*/

	if (animatable != NULL)
	{
		IRenderable *rend = dynamic_cast<IRenderable*>(animatable);
		if (rend != NULL)
			rend ->Render();
	}

	if (tcbKeyInterpolator != NULL)
		glPopMatrix();

	std::vector<Animation*>::iterator i;
	for (i = subAnims.begin(); i != subAnims.end(); i++)
		(*i) ->Render();

	glPopMatrix();
}

void Animation::AttachAnimatable(IAnimatable *animatable)
{
	if (this ->id == animatable ->GetId())
		this ->animatable = animatable;
	else
	{
		std::vector<Animation*>::iterator i;
		for (i = subAnims.begin(); i != subAnims.end(); i++)
			(*i) ->AttachAnimatable(animatable);
	}
}

void Animation::AttachAnimatable(IAnimatable **animatables, int count)
{
	for (int i = 0; i < count; i++)
		AttachAnimatable(animatables[i]);
}
